/**
*****************************************************************************************
*     Copyright(c) 2019-2020, Realtek Semiconductor Corporation. All rights reserved.
*****************************************************************************************
* @file     mijia_uart.c
* @brief    Source file for mijia uart.
* @details  Data types and functions.
* @author   hector_huang
* @date     2020-03-05
* @version  v1.0
* *************************************************************************************
*/
#include "mijia_uart.h"
#include <os_msg.h>
#include <os_task.h>
#include "rtl876x_nvic.h"
#include "rtl876x_rcc.h"
#include "rtl876x_rtc.h"
#include "rtl876x_uart.h"
#include "rtl876x_pinmux.h"
#include "mible_api.h"
#include "mible_log.h"

static mijia_uart_msg_t mijia_uart_msg;

static void *mijia_uart_evt_queue; /* evt queue */
static void *mijia_uart_msg_queue; /* msg queue */

static uint8_t mijia_uart_event;

static bool mijia_send_uart_msg(mijia_uart_msg_t *pmsg)
{
    /* send event to notify upper layer task */
    if (!os_msg_send(mijia_uart_msg_queue, pmsg, 0))
    {
        MI_LOG_ERROR("failed to send msg to mijia uart msg queue");
        return false;
    }

    if (!os_msg_send(mijia_uart_evt_queue, (void *)&mijia_uart_event, 0))
    {
        MI_LOG_ERROR("failed to send msg to mijia uart event queue");
        return false;
    }

    return true;
}

static void MI_UART0(void)
{
    uint8_t rx_data;
    uint32_t int_status;
    uint32_t line_error;
    uint8_t fifo_len;

    /* read interrupt id */
    int_status = UART_GetIID(UART);
    /* disable interrupt */
    UART_INTConfig(UART, UART_INT_RD_AVA | UART_INT_LINE_STS, DISABLE);

    if (UART_GetFlagState(UART, UART_FLAG_RX_IDLE) == SET)
    {
        UART_INTConfig(UART, UART_INT_IDLE, DISABLE);
        //DBG_DIRECT("UART0_FLAG_RX_IDLE: %d", mijia_uart_msg.len);
        mijia_send_uart_msg(&mijia_uart_msg);
        mijia_uart_msg.len = 0;
        UART_INTConfig(UART, UART_INT_IDLE, ENABLE);
    }

    switch (int_status)
    {
    /* tx fifo empty */
    case UART_INT_ID_TX_EMPTY:
        /* do nothing */
        break;
    /* rx data valiable */
    case UART_INT_ID_RX_LEVEL_REACH:
    case UART_INT_ID_RX_TMEOUT:
        fifo_len = UART_GetRxFIFOLen(UART);
        for (uint8_t i = 0; i < fifo_len; ++i)
        {
            UART_ReceiveData(UART, &rx_data, 1);
            mijia_uart_msg.data[mijia_uart_msg.len] = rx_data;
            mijia_uart_msg.len += 1;
            if (mijia_uart_msg.len >= MIJIA_UART_DATA_MAX_LEN)
            {
                mijia_send_uart_msg(&mijia_uart_msg);
                mijia_uart_msg.len = 0;
            }
        }
        break;
    /* receive line status interrupt */
    case UART_INT_ID_LINE_STATUS:
        line_error = UART->LSR;
        printe("data_uart_isr Line status error, fail = %d!", line_error);
        break;
    default:
        break;
    }

    /* enable interrupt again */
    UART_INTConfig(UART, UART_INT_RD_AVA | UART_INT_LINE_STS, ENABLE);
    return;
}

void mijia_uart_init(uint32_t tx_pin, uint32_t rx_pin, uint8_t evt_type, void *event_queue,
                     void *io_queue)
{
    UART_DeInit(UART);

    /* turn on UART clock */
    RCC_PeriphClockCmd(APBPeriph_UART0, APBPeriph_UART0_CLOCK, ENABLE);

    /* pinmux config */
    Pinmux_Config(P3_0, UART0_TX);
    Pinmux_Config(P3_1, UART0_RX);

    /* pad config */
    Pad_Config(P3_0, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_LOW);
    Pad_Config(P3_1, PAD_PINMUX_MODE, PAD_IS_PWRON, PAD_PULL_UP, PAD_OUT_DISABLE, PAD_OUT_LOW);

    /* uart init */
    UART_InitTypeDef uartInitStruct;
    UART_StructInit(&uartInitStruct);
    /* change default rx trigger level */
    uartInitStruct.rxTriggerLevel = UART_RX_FIFO_TRIGGER_LEVEL_8BYTE;
    uartInitStruct.idle_time = UART_RX_IDLE_2BYTE;
    UART_Init(UART, &uartInitStruct);
    /* enable rx interrupt and line status interrupt */
    UART_INTConfig(UART, UART_INT_RD_AVA | UART_INT_LINE_STS | UART_INT_IDLE, ENABLE);

    /*  Enable UART IRQ  */
    NVIC_InitTypeDef nvic_init_struct;
    nvic_init_struct.NVIC_IRQChannel = UART0_IRQn;
    nvic_init_struct.NVIC_IRQChannelCmd = ENABLE;
    nvic_init_struct.NVIC_IRQChannelPriority = 5;
    NVIC_Init(&nvic_init_struct);

    mijia_uart_event = evt_type;
    mijia_uart_evt_queue = event_queue;
    mijia_uart_msg_queue = io_queue;
    RamVectorTableUpdate(Uart0_VECTORn, MI_UART0);
}

void mijia_uart_deinit(void)
{
    UART_INTConfig(UART, UART_INT_RD_AVA | UART_INT_LINE_STS | UART_INT_IDLE, DISABLE);
    UART_DeInit(UART);
}
